package com.example.common.listener;

import com.alibaba.cloud.nacos.event.NacosDiscoveryInfoChangedEvent;
import com.example.common.constants.ServiceNames;
import com.example.common.grpc.ServiceInstanceRegistrar;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.context.ApplicationListener;
import org.springframework.scheduling.annotation.Scheduled;

import javax.annotation.PostConstruct;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * 抽象服务变更监听器
 * 提供通用的服务实例变化监听功能，子类可以监听特定的服务
 * 支持Nacos事件监听和定时检查双重机制
 */
@Slf4j
public abstract class AbstractServiceChangeListener implements ApplicationListener<NacosDiscoveryInfoChangedEvent> {

    protected final DiscoveryClient discoveryClient;
    protected final ServiceInstanceRegistrar serviceInstanceRegistrar;
    
    // 缓存上一次的实例列表，用于对比变化
    private final ConcurrentHashMap<ServiceNames, List<ServiceInstance>> lastInstanceMap = new ConcurrentHashMap<>();
    
    // 记录各服务实例数量变化
    private final ConcurrentHashMap<ServiceNames, AtomicInteger> instanceCountMap = new ConcurrentHashMap<>();
    
    // 记录服务状态变化时间戳
    private final ConcurrentHashMap<ServiceNames, Long> lastChangeTimeMap = new ConcurrentHashMap<>();

    protected AbstractServiceChangeListener(DiscoveryClient discoveryClient, ServiceInstanceRegistrar serviceInstanceRegistrar) {
        this.discoveryClient = discoveryClient;
        this.serviceInstanceRegistrar = serviceInstanceRegistrar;
    }

    @PostConstruct
    public void init() {
        log.info("服务监听器初始化完成，开始监听服务变化");
        // 初始化时检查一次所有服务状态
        //handleServiceChange();
    }

    @Override
    public void onApplicationEvent(NacosDiscoveryInfoChangedEvent event) {
        log.info("收到Nacos服务变更事件: eventType={}", event.getClass().getSimpleName());
        
        // 子类实现具体的服务监听逻辑
        handleServiceChange();
    }

    /**
     * 定时检查服务状态（每30秒检查一次）
     * 用于检测Nacos后台手动下线等事件
     */
 /*   @Scheduled(fixedRate = 15000)
    public void scheduledServiceCheck() {
        log.debug("执行定时服务状态检查");
        handleServiceChange();
    }*/

    /**
     * 处理服务变化，子类需要实现此方法
     */
    protected abstract void handleServiceChange();

    /**
     * 处理指定服务的变化（使用ServiceNames枚举）
     */
    /**
     * 处理指定服务的变化（使用字符串，保持向后兼容）
     */
    protected void handleServiceChange(ServiceNames serviceName) {
        List<ServiceInstance> currentInstances = discoveryClient.getInstances(serviceName.value());
        List<ServiceInstance> lastInstances = lastInstanceMap.get(serviceName);
        
        int currentCount = currentInstances.size();
        int lastCount = lastInstances != null ? lastInstances.size() : 0;
        
        // 检查是否有变化
        boolean hasChange = hasInstanceChange(currentInstances, lastInstances);
        
        if (hasChange) {
            log.info("{}实例数量变化: 上次={}, 当前={}", serviceName, lastCount, currentCount);
            
            // 打印当前可用实例信息
            if (!currentInstances.isEmpty()) {
                log.info("当前可用{}实例:", serviceName);
                currentInstances.forEach(instance -> {
                    log.info("  - {}:{} (元数据: {})", 
                            instance.getHost(), 
                            instance.getPort(),
                            instance.getMetadata());
                });
            } else {
                log.warn("⚠️ 当前没有可用的{}实例！", serviceName);
            }
            
            // 检测实例下线
            if (currentCount < lastCount) {
                int downCount = lastCount - currentCount;
                log.warn("🚨 {}有{}个实例下线！当前可用实例数: {}", serviceName, downCount, currentCount);
                
                // 对比具体下线的实例
                if (lastInstances != null) {
                    for (ServiceInstance lastInstance : lastInstances) {
                        boolean stillExists = currentInstances.stream()
                                .anyMatch(current -> isSameInstance(current, lastInstance));
                        
                        if (!stillExists) {
                            log.warn("🚨 {}实例下线: {}:{}", 
                                    serviceName, lastInstance.getHost(), lastInstance.getPort());
                        }
                    }
                }
                this.serviceInstanceRegistrar.forceRefreshService(serviceName);
            }
            
            // 检测实例上线
            if (currentCount > lastCount) {
                int upCount = currentCount - lastCount;
                log.info("✅ {}有{}个实例上线！当前可用实例数: {}", serviceName, upCount, currentCount);
                this.serviceInstanceRegistrar.forceRefreshService(serviceName);
            }
            
            // 记录变化时间
            lastChangeTimeMap.put(serviceName, System.currentTimeMillis());
            
            // 调用子类的具体处理逻辑
            onServiceInstanceChange(serviceName.value(), currentInstances, lastInstances);
        } else {
            log.debug("{}实例数量无变化: 当前={}", serviceName, currentCount);
        }
        
        // 更新缓存
        lastInstanceMap.put(serviceName, currentInstances);
        getInstanceCount(serviceName).set(currentCount);
    }

    /**
     * 根据服务名获取对应的枚举
     */
    private ServiceNames getServiceEnum(String serviceName) {
        for (ServiceNames service : ServiceNames.values()) {
            if (service.value().equals(serviceName)) {
                return service;
            }
        }
        // 如果找不到对应的枚举，返回null，但这种情况不应该发生
        log.warn("未找到服务名对应的枚举: {}", serviceName);
        return null;
    }

    /**
     * 检查实例列表是否有变化
     */
    private boolean hasInstanceChange(List<ServiceInstance> currentInstances, List<ServiceInstance> lastInstances) {
        if (lastInstances == null) {
            return !currentInstances.isEmpty(); // 首次检查，如果有实例就算有变化
        }
        
        if (currentInstances.size() != lastInstances.size()) {
            return true; // 数量不同
        }
        
        // 检查具体实例是否有变化
        for (ServiceInstance current : currentInstances) {
            boolean found = lastInstances.stream()
                    .anyMatch(last -> isSameInstance(current, last));
            if (!found) {
                return true; // 发现新实例
            }
        }
        
        for (ServiceInstance last : lastInstances) {
            boolean found = currentInstances.stream()
                    .anyMatch(current -> isSameInstance(current, last));
            if (!found) {
                return true; // 发现丢失的实例
            }
        }
        
        return false; // 没有变化
    }

    /**
     * 服务实例变化时的回调方法，子类可以重写此方法
     */
    protected void onServiceInstanceChange(String serviceName, List<ServiceInstance> currentInstances, List<ServiceInstance> lastInstances) {
        // 默认实现为空，子类可以重写
    }

    /**
     * 判断是否为同一个实例
     */
    protected boolean isSameInstance(ServiceInstance instance1, ServiceInstance instance2) {
        return instance1.getHost().equals(instance2.getHost()) && 
               instance1.getPort() == instance2.getPort();
    }

    /**
     * 获取指定服务的当前实例数（使用ServiceNames枚举）
     */
    protected int getCurrentInstanceCount(ServiceNames serviceName) {
        return getInstanceCount(serviceName).get();
    }


    /**
     * 检查指定服务是否可用（使用ServiceNames枚举）
     */
    protected boolean isServiceAvailable(ServiceNames serviceName) {
        return getCurrentInstanceCount(serviceName) > 0;
    }

    /**
     * 获取指定服务的实例数量记录器
     */
    private AtomicInteger getInstanceCount(ServiceNames serviceName) {
        return instanceCountMap.computeIfAbsent(serviceName, k -> new AtomicInteger(0));
    }

    /**
     * 获取指定服务的当前实例列表
     */
    protected List<ServiceInstance> getCurrentInstances(String serviceName) {
        return discoveryClient.getInstances(serviceName);
    }

    /**
     * 获取指定服务的上次实例列表（使用ServiceNames枚举）
     */
    protected List<ServiceInstance> getLastInstances(ServiceNames serviceName) {
        return lastInstanceMap.get(serviceName);
    }

    /**
     * 获取指定服务的上次实例列表（使用字符串，保持向后兼容）
     */
    protected List<ServiceInstance> getLastInstances(String serviceName) {
        ServiceNames serviceEnum = getServiceEnum(serviceName);
        return serviceEnum != null ? getLastInstances(serviceEnum) : null;
    }

    /**
     * 获取指定服务的最后变化时间（使用ServiceNames枚举）
     */
    public Long getLastChangeTime(ServiceNames serviceName) {
        return lastChangeTimeMap.get(serviceName);
    }

    /**
     * 获取指定服务的最后变化时间（使用字符串，保持向后兼容）
     */
    public Long getLastChangeTime(String serviceName) {
        ServiceNames serviceEnum = getServiceEnum(serviceName);
        return serviceEnum != null ? getLastChangeTime(serviceEnum) : null;
    }

    /**
     * 手动触发服务检查
     */
    public void manualCheck() {
        log.info("手动触发服务状态检查");
        handleServiceChange();
    }
} 